// Package middleware
// @File: auth.go
// @Description: 认证中间件
// @Author: YaoRuiQi
// @Date: 2025/8/23 02:50

package middleware

import (
	"GinStandardTemplate/internal/constant"
	"GinStandardTemplate/internal/pkg/bizerror"
	"GinStandardTemplate/internal/pkg/codes"
	"GinStandardTemplate/internal/pkg/contextUtils"
	"GinStandardTemplate/internal/pkg/jwt"
	"GinStandardTemplate/internal/pkg/response"
	i18nUtils "GinStandardTemplate/utils/i18n"
	"GinStandardTemplate/utils/logger"
	"strings"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// 无需登陆接口
var skipVerifyPath = map[string]struct{}{
	"/api/login": {},
}

// checkToken
//
//	@Description: 检查token，解析token，获取用户信息
//	@return *jwt.Claims 解析后的用户信息
//	@return bool true解析成功 false解析失败
func checkToken(token string) (*jwt.UserClaims, bool) {
	if token == "" {
		return nil, false
	}
	if claims, err := jwt.JWTManager.ParseJWT(token); err != nil {
		logger.Logger.Error("解析token失败", zap.Error(err), zap.String("token", token))
		return nil, false
	} else {
		return claims, true
	}
}

// getUserInfo
//
//	@Description: TODO: 获取用户信息，这里暂时只返回用户角色和是否禁用。实际根据业务需要进行修改
//	@param userID 用户ID
func getUserInfo(userID int64) (string, bool, error) {
	role := "admin"
	isDisable := false
	var getUserInfoErr error // TODO: 模拟获取用户信息失败
	return role, isDisable, getUserInfoErr
}

// checkHasPermission 验证具有给定角色、ID 和名称的用户是否有权访问指定的 API 路径。
func checkHasPermission(userRole, apiPath string) bool {
	// 如果用户是管理员，则返回 true
	if userRole == constant.RoleAdmin {
		return true
	}
	// TODO: 处理非管理员用户的权限验证逻辑。这里只限制非管理员不能访问 /api/admin 开头的 API
	if strings.HasPrefix(apiPath, "/api/admin") {
		return false
	}
	return true
}

// HttpIdentityAuthentication
//
//	@Description: http请求身份验证
func httpIdentityAuthentication(ctx *contextUtils.RequestContext, token, path string) (*jwt.UserClaims, *bizerror.BizError) {
	// 检查token有效性
	claims, tokenValid := checkToken(token)
	if !tokenValid {
		return nil, bizerror.NewBizError(
			codes.UserUnauthorized,
			i18nUtils.GetMessage(ctx, codes.UserUnauthorized.MessageID(), nil),
		)
	}

	// 获取用户信息
	userRole, userIsDisable, err := getUserInfo(claims.UserID)
	if err != nil {
		logger.Logger.Error("身份认证中间价获取用户信息失败", zap.String("requestID", ctx.RequestID), zap.Error(err))
		return nil, bizerror.NewBizError(
			codes.InternalError,
			i18nUtils.GetMessage(ctx, codes.InternalError.MessageID(), nil),
		)
	}

	// 检查用户状态
	if userIsDisable {
		return nil, bizerror.NewBizError(
			codes.UserDisabled,
			i18nUtils.GetMessage(ctx, codes.UserDisabled.MessageID(), nil),
		)
	}

	// 检测用户角色权限
	if !checkHasPermission(userRole, path) {
		ctx.Logger.Warn(
			"用户无权限行为",
			zap.String("path", path),
			zap.Int64("userId", claims.UserID),
			zap.String("userRole", claims.UserRole),
		)
		return nil, bizerror.NewBizError(
			codes.UserForbidden,
			i18nUtils.GetMessage(ctx, codes.UserForbidden.MessageID(), nil),
		)
	}

	return claims, nil
}

// WebsocketIdentityAuthentication
//
//	@Description: websocket请求身份认证
func websocketIdentityAuthentication(ctx *contextUtils.RequestContext, token, path string) (*jwt.UserClaims, *bizerror.BizError) {
	var claims *jwt.UserClaims

	// 检查token有效性
	var tokenValid bool
	claims, tokenValid = checkToken(token)
	if !tokenValid {
		return nil, bizerror.NewBizError(
			codes.UserUnauthorized,
			i18nUtils.GetMessage(ctx, codes.UserUnauthorized.MessageID(), nil),
		)
	}

	return claims, nil
}

// AuthMiddleware
//
//	@Description: 认证中间件
//	@return gin.HandlerFunc
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		path := c.Request.URL.Path
		// 在上一层国际化中间价已经将自定义上下文为nil的情况处理了，这里不需要考虑nil
		ctx, _ := contextUtils.FromContext(c.Request.Context())
		var err *bizerror.BizError
		var userData *jwt.UserClaims

		if _, exists := skipVerifyPath[path]; exists {
			// 如果请求路径在跳过验证的列表中，则不进行认证
			err = nil
			userData = nil
		} else if strings.HasPrefix(path, "/api") {
			// 如果是http请求，则进行认证
			token := c.GetHeader("Authorization")
			userData, err = httpIdentityAuthentication(ctx, token, path)
		} else if strings.HasPrefix(path, "/ws") {
			// 如果是websocket请求，则进行认证
			token := c.Query("Authorization")
			userData, err = websocketIdentityAuthentication(ctx, token, path)
		} else {
			ctx.Logger.Error("认证中间价获取到异常请求URL", zap.String("path", path))
			err = bizerror.NewBizError(codes.InvalidURL, "error.InvalidURL")
		}

		if err != nil {
			response.JSONResponse(c, err.Code.Code(), err.Error(), nil)
			c.Abort()
		}

		// 更新上下文，增加用户信息
		c.Request = c.Request.WithContext(contextUtils.NewRequestContext(
			c.Request.Context(), &contextUtils.RequestContext{
				RequestID: ctx.RequestID,
				Localizer: ctx.Localizer,
				UserData:  userData,
			},
		))

		c.Next()
	}
}
